#include "CGameEnv.h"

//Constructor
CGameEnv::CGameEnv()
{
    done = false;
    resolutionX = 1024;
    resolutionY = 768;
    keystate = NULL; // Set keystate pointer to null.
    bMouseLeft = false;
    bMouseRight = false;

    CGameEnv::initializeAll();
    printf("GameEnv.Ctor finish\n");
}

void CGameEnv::initializeAll()
{
    this->initializeSDL();
    this->initializeGL();
}

/*
CGameEnv::~CGameEnv()
{
}
*/

//Public
void CGameEnv::startGame()
{
    while(!done)//Game loop
    {
        // Call virtual functions overrided by game.
        this->tick();
        this->drawFrame();
        this->handleEvents();

        SDL_Delay(1); // Dont hog all cpu time. Play nice.
    }

    this->cleanUp();
    printf("GameEnv.startGame() GameLoop-finished. Returning to int main()\n");
    return;
}

//Override.
void CGameEnv::tick()
{

}

//Override
void CGameEnv::drawFrame()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 1.0f, -10.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(0.87f, -0.5f, -10.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-0.87f, -0.5f, -10.0f);
    glEnd();

    CVectorLetters vectorLetters; // Temporary
    vectorLetters.drawVectorText("Override drawFrame() please!", 3, 2, 100,150);

    SDL_GL_SwapBuffers();
}


/*************
 * Poll events.
 *************/
//Override this, but call base for Esc key and window-X.
void CGameEnv::handleEvents()
{
    SDL_PollEvent(&event); // Waiting is more efficient, check: http://www.meandmark.com/sdlopenglpart6.html

    // Get mouse and keystate
    //SDL_GetMouseState(&mouseX, &mouseY);
    keystate = SDL_GetKeyState(NULL); // This is sweet! Just use "if(keystate[SDLK_UP]) doStuffOnButtonUp()"

    if( event.type == SDL_KEYDOWN )
    {
        if(event.key.keysym.sym==SDLK_ESCAPE)
        {
            done = true;
        }
    }else if(event.type == SDL_MOUSEMOTION)
    {
        mouseX = event.motion.x;
        mouseY = event.motion.y;
    }else if(event.type == SDL_MOUSEBUTTONDOWN ) //If a mouse button was pressed
    {
        if( event.button.button == SDL_BUTTON_LEFT )
        {
            bMouseLeft = true;
        }else if(event.button.button == SDL_BUTTON_RIGHT)
        {
            bMouseRight = true;
        }
    }else if( event.type == SDL_MOUSEBUTTONUP ) //If a mouse button was released
    {
        if( event.button.button == SDL_BUTTON_LEFT )
        {
            bMouseLeft = false;
        }else if(event.button.button == SDL_BUTTON_RIGHT)
        {
            bMouseRight = false;
        }
    }else if(event.type == SDL_QUIT)
    {
        std::cout<< "SDL_QUIT" << std::endl;
        done = true;
    }else if(event.type == SDL_VIDEORESIZE)
    {
        // We get heaps of VIDEORESIZE events when the window is streched, but there is no change in reize.w/h before the mouse is released.
        // One more thing. The SDL Docs say you should also call SDL_VideoMode, but this destroys the opengl context, and all textures must be reloaded :( This really sucks.
        // http://www.gamedev.net/community/forums/topic.asp?topic_id=406165
        // if we dont call SDL_VideoMode, everything seems to work fine except the mouse that caps out at the original window width/height. This can be worked around
        // using relative coords for mouse.
        // Things might be better in GLFW, I dunno.
        if(event.resize.w == resolutionX && event.resize.h == resolutionY)
        {
            //printf("GameEnv.handleEvents(): no need to resize\n");
        }
        else
        {
            resolutionX = event.resize.w;
            resolutionY = event.resize.h;
            resize(resolutionX,resolutionY);
        }
    }
}

/*************
 * Init video and set video mode. Also, fix the console.
 *************/
void CGameEnv::initializeSDL()
{
    printf("CGameEnv says.initializeSDL() start\n");

    // Because of SDL, the console is defaultly redirected to a file. We don't want this. redir back to console.
    // Should really fclose(ctt) at cleanUp(), but it stopped working :S. Do this before SDL_Init
    ctt = fopen("CON", "w" );

    SDL_Init(SDL_INIT_VIDEO); // Takes about 100 ms

    // This is needed for the console to work because of SDL+mingw peculiarities.
    // Check out Easca's posts here: http://www.gamedev.net/community/forums/topic.asp?topic_id=299349&PageSize=25&WhichPage=2
    //FILE * ctt = fopen("CON", "w" ); // Should really fclose(ctt) at cleanUp(), but it stopped working :S
    // When using the mingw ready compiled SDL .lib and .h files, console output goes to a file. So, change it:
    // Redirect standard output to console. Its also possible to recompile SDL to achieve this.
    freopen( "CON", "wt", stdout ); // When debugging we have to close stdout when we are done with it, at least with codeblocks (and mingw in generall I guess)
    freopen( "CON", "wt", stderr ); // Also stderr.
    //freopen( "filename", "wt", stdout ); // Alternatively, output to a file. This is SDL's default.


    SDL_WM_SetCaption("GameEnv 0.1", NULL);

    // Because we are using opengl, activate doublebuf, set color to 32 bit color (8+8+8+8)
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
    // Set Depth buffer size
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);

    // SDL_SetVideoMode takes about 800 ms on my pc.
    drawContext = SDL_SetVideoMode(resolutionX, resolutionY, 32, SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE);
    if(drawContext == NULL)
    {
        printf("GameEnv::initializeSDL() FAIL: Couldn't SetVideoMode\n");
        cleanUp();
    }

    keystate = SDL_GetKeyState(NULL); // Move this to a initInput method?


    printf("CGameEnv says.initializeSDL() finish\n");
}

/*************
 * Set CLS Color, Depth, DepthFunc, Enable DepthTest, Set shademodel, check available GL_Versions AND resize window.
 *************/
void CGameEnv::initializeGL()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);

    GLeeInit(); // no longer needed in new GLee version??

    printf("GameEnv.initializeGL(): Supported OpenGL versions:");
    if(GLEE_VERSION_1_2) printf("1.2 ");
    if(GLEE_VERSION_1_3) printf("1.3 ");
    if(GLEE_VERSION_1_4) printf("1.4 ");
    if(GLEE_VERSION_1_5) printf("1.5 ");
    if(GLEE_VERSION_2_0) printf("2.0 ");
    if(GLEE_VERSION_2_1) printf("2.1 ");
    if(GLEE_VERSION_3_0) printf("3.0 ");
    printf("\n");

    GLint texSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
    printf("GL_MAX_TEXTURE_SIZE = %i\n", texSize);

    resize(resolutionX, resolutionY);
}

bool CGameEnv::mouseDown(int button)
{
    if(button == 1) return bMouseLeft;
    else if(button == 2) return bMouseRight;
    return false;
}

/*************
 * Is called from eventHandler when a resize event is recieved.
 * Resizes viewport and sets new perspective with correct aspect ratio.
 *************/
void CGameEnv::resize(int width, int height)
{
    if(height==0) // Prevent div by 0 error
        height = 1;

    glViewport(0,0,width,height);

    // Reset projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 1.0f, 2048.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    printf("GameEnv::resize(%ix%i)\n", width, height);
}

/*************
 * Serves as destructor.
 * You may override, but call base.
 *************/
void CGameEnv::cleanUp()
{
    printf("GameEnv.cleanUp()\n");

    // Stop using the console, allow the codeblocks debugger use it. This means flushing the stream and closing it.
    // Anything else makes it hard for code::blocks to close the console
    //fflush(stdout);
    fclose(stdout);
    fclose(stderr);

    // should really close console. but it seems that code::blocks or mingw needs it open inorder to close the program when running in debug/console mode.
    //fclose(ctt);

    SDL_Quit();
}
